package com.gitee.sxran.dynagraphql;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * 异步的.
 */
public abstract class DynGraphqlResolverAsync extends DynGraphqlResolver {
    final List<String> threadList;
    final Map<String, Future<Object>> threadMap ;
    /**
     * @param json 数组
     */
    public DynGraphqlResolverAsync(JSONArray json) {
        super(json);
        threadList = new ArrayList<>(size);
        threadMap = new HashMap<>(size);
    }

    @Override
    public final Object execAction(JSONObject jsonObject, String asName) throws ExecutionException, InterruptedException {
        //
        Callable<Object> callableThread = newCallable(jsonObject,
                (x , y) -> {
                    return super.execAction(x,y);
                }
                ,asName);
        // 异步执行.
        Future<Object> objectFuture = ThreadUtil.execAsync(callableThread);
        // 放入池中.
        threadMap.putIfAbsent(asName,objectFuture);
        // 先放回""的。
        return "";
    }

    @Override
    public Object getValueByPathForResult(Object value) throws ExecutionException, InterruptedException {
        String expression = String.valueOf(value);
        String resultAsName =  StrUtil.subBefore(expression, '.', false);
        // 只获得第一个.对象    result.user.name   -> result ;
        Future<Object> future = this.threadMap.get(resultAsName);
        if(future == null)
            throw new NullPointerException(StrUtil.format("[{}],resultAsName=[{}] not exsits",expression,resultAsName));
        threadList.add(resultAsName);
        // 阻塞.
        future.get();
        return super.getValueByPathForResult(value);
    }

    /**
     * @param jsonObject
     * @param execAction
     * @param asName
     * @return
     */
    protected  Callable<Object> newCallable(JSONObject jsonObject, ExecAction execAction, String asName){
        return () -> {
            //
            Object result = execAction.exec(jsonObject,asName);
            this.resultJson.put(asName,result);
            return result;
        };
    }


    @Override
    public final void destroy() {
        // 阻塞执行内容。
        threadMap.entrySet().forEach( entry -> {
            String name = entry.getKey();
            Future<Object> future = entry.getValue();
            // 不包含才进去阻塞。
            if (!threadList.contains(name)) {
                try {
                    future.get();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

        });
    }

    /**
     * 包装一下DynGraphqlResolver.execAction的用法。
     * 供子类调用。
     */
    public interface ExecAction{
        Object exec(JSONObject jsonObject, String asName) throws Exception;
    }
}
